/*
 * @Author: xiaosihan 
 * @Date: 2024-07-29 12:22:45 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2025-08-23 16:33:05
 */

import OSS, { STS } from "ali-oss";
import database from "../database";
import ServiceBase from "./ServiceBase";
import { last, get } from "lodash";
import dotenv from 'dotenv';
import axios from 'axios';
import tinify from 'tinify';
import fs from 'fs';
import path from 'path';
import express from 'express';
dotenv.config({ path: '.env', quiet: true });

// 定义静态方法优化图片
// 不应该在构造函数中进行异步操作
const optimizeImages = async (ossService: OssService) => {
    while (await ossService.optimize_image()) {
        await new Promise(resolve => setTimeout(resolve, 0));
    }
};

// OSS服务类
export default class OssService extends ServiceBase {

    constructor(req: express.Request = {} as express.Request, res: express.Response = {} as express.Response) {
        super(req, res);
    }

    // 配置 OSS 客户端
    private oss = new OSS({
        region: process.env.region || "",
        accessKeyId: process.env.accessKeyId || "",
        accessKeySecret: process.env.accessKeySecret || "",
        bucket: process.env.bucket || "",
    });

    private sts = new STS({
        accessKeyId: "LTAI5tNDqBuTfiLiYanwWJfK",
        accessKeySecret: "bh1hWeoaIXxCDZKkCTAahGLOi4Rjzk",
    });

    // 获取OSS STS凭证
    get_oss_sts = async (params: Record<string, any>) => {
        const result = await this.sts.assumeRole('acs:ram::1033195204594803:role/RamOssTest', ``, 3000, 'sessiontest');
        return result.credentials;
    };

    // 获取文件列表
    get_file_list = async (params: Record<string, any>) => {
        let marker = "";
        let allUrls: string[] = [];
        let pageSize = 1000;
        let goon = true;

        do {
            const result = await this.oss.listV2({
                "start-after": marker.replace("http://www-3dkeshihua.oss-cn-shanghai.aliyuncs.com/", ""),
                'max-keys': String(pageSize)
            }, {
                timeout: 864000
            });

            // 是否继续
            goon = (result.objects.length === pageSize);

            const urls = result.objects.map(object => {
                return decodeURIComponent(object.url);
            });

            marker = urls.length > 0 ? last(urls)! : "";

            const filteredUrls = urls.filter(url => {
                const allowedExtensions = ['jpg', 'jpeg', 'png', 'webp', 'glb'];
                const extension = url.split('.').pop()?.toLowerCase();
                return extension && allowedExtensions.includes(extension);
            });

            allUrls = [...allUrls, ...filteredUrls];

            // 把 urls 的数据都添加到 database.oss_file 中字段是url
            await database.oss_file.bulkCreate(filteredUrls.map(url => {
                const suffix = url.split('.').pop()?.toLowerCase();
                return {
                    url,
                    suffix
                };
            }), {
                logging: false,
                // 添加ignoreDuplicates选项，忽略重复键错误
                ignoreDuplicates: true
            });
        } while (goon);

        return { urls: allUrls };
    };

    // 优化一张图片
    optimize_image = async (): Promise<boolean> => {
        // 1.从database.oss_file中获取一张未优化的图片地址
        const ossFile = await database.oss_file.findOne({
            where: {
                optimized: false,
                used: "used",
                suffix: ['jpg', 'jpeg', 'png', 'webp']
            }
        });

        if (!ossFile) {
            console.log("没有未优化的图片");
            return false;
        }

        const url = ossFile.dataValues.url;

        // 获取TinyPNG API密钥
        const apiUrl = 'https://tinypng-key-buzpejwefi.cn-hangzhou.fcapp.run/tiny_api/get_key_by_conut';
        const tingPngKey = await axios
            .get(encodeURI(apiUrl), {
                params: { conut: 1 }
            })
            .then((res) => get(res, ["data", "data", "ting_png_key"], ""))
            .catch(() => "");

        if (!tingPngKey) {
            console.error("无法获取TinyPNG API密钥");
            return false;
        }

        // 设置TinyPNG密钥
        tinify.key = tingPngKey;

        // 创建临时文件路径
        const localPath = path.join(__dirname, `${new Date().valueOf()}.${last(url.split("."))}`);

        try {
            // 3.从网络URL下载图片到本地
            const encodedUrl = encodeURI(url);
            const res = await axios.get(encodedUrl, {
                responseType: 'stream'
            });
            const writer = fs.createWriteStream(localPath);
            res.data.pipe(writer);
            await new Promise<void>((resolve, reject) => {
                writer.on('finish', resolve);
                writer.on('error', reject);
            });

            // 4.优化本地图片
            const source = tinify.fromFile(localPath);
            await source.toFile(localPath);

            // 5.上传到OSS
            const ossPath = url.replace("http://www-3dkeshihua.oss-cn-shanghai.aliyuncs.com/", "");
            const encodedOssPath = encodeURI(ossPath);
            await this.oss.put(encodedOssPath, localPath);

            console.log("优化图片成功", url);
            return true;
        } finally {
            // 6.删除临时文件
            try {
                const files = fs.readdirSync(__dirname);
                files.forEach(file => {
                    if (file.endsWith('.jpg') || file.endsWith('.jpeg') || file.endsWith('.png') || file.endsWith('.webp')) {
                        fs.unlinkSync(path.join(__dirname, file));
                    }
                });
            } catch (cleanupError) {
                console.error("清理临时文件失败:", cleanupError);
            }

            // 7.更新数据库状态
            await database.oss_file.update(
                { optimized: true },
                { where: { url } }
            );
        }
    };

    // 优化图片的处理器（遵循代码模板规范）
    optimize_image_handler = async (params: Record<string, any>) => {
        const result = await this.optimize_image();
        if (result) {
            return { success: true, message: "图片优化成功" };
        } else {
            return { success: false, message: "没有未优化的图片或优化失败" };
        }
    };
}

// 创建并导出单例实例
const ossService = new OssService();
export { ossService };